package com.lee.user.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import com.lee.common.exception.ApplicationException;
import com.lee.common.model.AppResult;
import com.lee.common.model.ResultCode;
import com.lee.common.model.User;
import com.lee.common.utils.MD5Util;
import com.lee.common.utils.StringUtil;
import com.lee.common.utils.UUIDUtil;
import com.lee.user.mapper.UserMapper;
import com.lee.user.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: lishuo
 * Date: 2023-09-27
 * Time: 21:15
 */
@Slf4j
@Service
public class UserServiceImpl implements IUserService {
    // 从配置文件中读取
    @Value("${forum.headerimage.url}")
    private String headerimageUrl;

    @Value("${forum.headermapper.url}")
    private String headermapperUrl;

    @Value("${forum.codeimage.url}")
    private String codeimageUrl;

    @Value("${forum.codemapper.url}")
    private String codemapperUrl;

    @Resource
    private UserMapper userMapper;

    @Override
    public void createNormalUser(User user) {
        // 1.非空校验
        if (user == null || StringUtil.isEmpty(user.getUsername())
        || StringUtil.isEmpty(user.getNickname()) || StringUtil.isEmpty(user.getPassword())
        || StringUtil.isEmpty(user.getSalt())) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2.根据用户名查询用户信息
        User existsUser = userMapper.selectByUsername(user.getUsername());
        // 2.1判断用户是否存在
        if (existsUser != null) {
            // 打印日志
            log.info(ResultCode.FAILED_USER_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
        }

        // 3.新增用户
        // 3.1设置默认值
        user.setGender((byte) 2);
        user.setArticleCount(0);
        user.setIsAdmin((byte) 0);
        user.setState((byte) 0);
        user.setDeleteState((byte) 0);
        // 当前时间
        Date date = new Date();
        user.setCreateTime(date);
        user.setUpdateTime(date);
        // 3.2写入数据库
        int row = userMapper.insertSelective(user);
        if (row != 1) {
            // 打印日志
            log.info(ResultCode.FAILED_CREATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CREATE));
        }
        // 打印日志
        log.info(ResultCode.SUCCESS.toString()+"username = "+user.getUsername()+".");
    }

    @Override
    public User selectByUsername(String username) {
        // 1.参数校验
        if (StringUtil.isEmpty(username)) {
            // 打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString()+"username = "+username);
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        // 2.返回查询结果
        return userMapper.selectByUsername(username);
    }

    @Override
    public User login(String username, String password) {
        // 1.参数校验
        if (StringUtil.isEmpty(username) || StringUtil.isEmpty(password)) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2.根据用户名查询用户信息
        User user = selectByUsername(username);
        // 3.判断用户是否存在
        if (user == null) {
            // 打印日志
            log.warn(ResultCode.FAILED_LOGIN.toString()+"username = "+username);
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        // 4.验证密码是否正确
        String encrptPassword = MD5Util.md5Salt(password,user.getSalt());
        if (!encrptPassword.equalsIgnoreCase(user.getPassword())) {
            // 打印日志
            log.warn(ResultCode.FAILED_LOGIN.toString()+"密码错误:username = "+username);
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        // 5.登录成功，返回用户信息
        // 打印日志
        log.info("登录成功：username = " + username);
        return user;
    }

    @Override
    public User selectById(Long id) {
        // 1.校验参数
        if (id == null) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2.根据用户id查询用户信息
        User user = userMapper.selectByPrimaryKey(id);
        // 3.返回用户信息
        return user;
    }

    @Override
    public void addOneArticleCountById(Long id) {
        // 1.参数校验
        if (id == null || id <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2.根据id查询用户信息
        User user = userMapper.selectByPrimaryKey(id);
        // 判断查询结果是否有效
        if (user == null) {
            // 打印日志
            log.warn(ResultCode.ERROR_IS_NULL.toString()+"user id = "+id);
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.ERROR_IS_NULL.toString()));
        }
        // 3.用户帖子数量+1
        // 3.1构造信息
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setArticleCount(user.getArticleCount()+1);
        // 3.2调用DAO更新数据
        int updateRow = userMapper.updateByPrimaryKeySelective(updateUser);
        // 4.校验受影响的函数
        if (updateRow <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED+"受影响的行数不等于1.");
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }
        // 5.打印更新成功日志
        log.info("用户 user id = "+user.getId()+"帖子数量+1");

    }

    @Override
    public void subOneArticleCountById(Long id) {
        // 1.参数校验
        if (id == null || id <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2.根据板块id查询用户信息
        User user = userMapper.selectByPrimaryKey(id);
        // 判断查询结果是否有效
        if (user == null) {
            // 打印日志
            log.warn(ResultCode.ERROR_IS_NULL.toString()+"user id = "+id);
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.ERROR_IS_NULL.toString()));
        }
        // 3.构造更新对象
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setArticleCount(user.getArticleCount()-1);
        // 判断ArticleCount是否小于0
        if (updateUser.getArticleCount() < 0) {
            // 如果小于0则设置为0
            updateUser.setArticleCount(0);
        }
        // 4.调用DAO更新文章数量
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        // 4.校验受影响的函数
        if (row <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED+"受影响的行数不等于1.");
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }
    }

    @Override
    public void modifyInfo(User user) {
        // 1.校验参数
        if (user == null || user.getId() <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2.根据用户Id查询用户是否存在
        User existUser = userMapper.selectByPrimaryKey(user.getId());
        if (existUser == null || existUser.getDeleteState() == 1) {
            // 打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString()+"user id = "+user.getId());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS.toString()));
        }
        // 3. 定义一个标志位
        boolean checkAttr = false; // false表示没有校验通过

        // 4.定义一个用于更新的用户对象
        User updateUser = new User();
        updateUser.setId(user.getId());
        // 4.1校验用户名(登录名，唯一)
        if (!StringUtil.isEmpty(user.getUsername()) && !user.getUsername().equals(existUser.getUsername())) {
            // 校验是否已存在该登录名
            User checkUser = userMapper.selectByUsername(user.getUsername());
            if (checkUser != null) {
                // 打印日志
                log.warn(ResultCode.FAILED_USER_EXISTS.toString()+"user name = "+user.getUsername());
                // 抛出异常
                throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
            }
            // 修改更新对象
            updateUser.setUsername(user.getUsername());
            // 修改标志位
            checkAttr = true;
        }
        // 4.2校验昵称
        if (!StringUtil.isEmpty(user.getNickname()) && !user.getNickname().equals(existUser.getNickname())) {
            // 修改更新对象
            updateUser.setNickname(user.getNickname());
            // 修改标志位
            checkAttr = true;
        }
        // 4.3校验姓别
        if (user.getGender() != null && user.getGender() != existUser.getGender()
                && (user.getGender() == 0 || user.getGender() == 1 || user.getGender() == 2)) {
            // 修改更新对象
            updateUser.setGender(user.getGender());
            // 修改标志位
            checkAttr = true;
        }
        // 4.4校验邮箱
        if (!StringUtil.isEmpty(user.getEmail()) && !user.getEmail().equals(existUser.getEmail())) {
            // 修改更新对象
            updateUser.setEmail(user.getEmail());
            // 修改标志位
            checkAttr = true;
        }
        // 4.5校验电话
        if (!StringUtil.isEmpty(user.getPhoneNum()) && !user.getPhoneNum().equals(existUser.getPhoneNum())) {
            // 修改更新对象
            updateUser.setPhoneNum(user.getPhoneNum());
            // 修改标志位
            checkAttr = true;
        }
        // 4.6校验个人简介
        if (!StringUtil.isEmpty(user.getRemark()) && !user.getRemark().equals(existUser.getRemark())) {
            // 修改更新对象
            updateUser.setRemark(user.getRemark());
            // 修改标志位
            checkAttr = true;
        }
        // 5.通过标志位判断是否校验通过
        if (checkAttr == false) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 6.调用DAO更新个人信息
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        // 7.校验受影响的函数
        if (row <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED+"受影响的行数不等于1.");
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }



    }

    @Override
    public void modifyPassword(Long id, String newPassword, String oldPassword) {
        // 1.校验参数
        if (id == null || id <= 0 || StringUtil.isEmpty(newPassword) || StringUtil.isEmpty(oldPassword)) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2.根据id查询用户是否存在
        User user = userMapper.selectByPrimaryKey(id);
        if (user == null) {
            // 打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        // 3.校验老密码是否正确
        String oldEncrptedPassword = MD5Util.md5Salt(oldPassword,user.getSalt());
        if (!oldEncrptedPassword.equalsIgnoreCase(user.getPassword())) {
            // 打印日志
            log.warn("UserServiceImpl-modifyPassword 原密码错误!");
            // 抛出异常
            throw new ApplicationException(AppResult.failed("原密码错误!"));
        }
        // 4.封装更新对象
        User updateUser = new User();
        // 设置新盐
        String newSalt = UUIDUtil.UUID_32();
        String newEncrptedPassword = MD5Util.md5Salt(newPassword,newSalt);
        updateUser.setId(id);
        updateUser.setSalt(newSalt);
        updateUser.setPassword(newEncrptedPassword);
        // 4.调用DAO更新密码
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        // 校验受影响行数
        if (row <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED+"受影响的行数不等于1.");
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }
    }

    @Override
    public User uploadPhoto(MultipartFile file,Long userId) throws IOException {
        // 1.校验参数
        if (file == null || userId == null || userId <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }

        // 2.生成一个唯一 id
        String id = UUIDUtil.UUID_32();
        // 3.获取源文件后缀名
        String suffix = file.getOriginalFilename().
                substring(file.getOriginalFilename().lastIndexOf("."));
        // 判断文件类型是否符合要求（要求头像格式为.png或.jpg）
        if (!suffix.equals(".jpg") && !suffix.equals(".png") ) {
            // 打印日志
            log.warn("头像类型错误");
            // 抛出异常
            throw new ApplicationException(AppResult.failed("头像类型错误"));
        }
        // 4.设置文件完整保存路径
//        String path = "/forumImage/"+id+suffix;
//        String path = "D:/forumImage/"+id+suffix;
        String path = headerimageUrl+id+suffix;

        file.transferTo(new File(path));

        // 5.将头像地址更新到数据库
        // 封装更新对象
//        path = "./userPhoto/"+id+suffix;
        path = headermapperUrl+id+suffix;

        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setAvatarUrl(path);
        // 调用DAO
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        // 校验受影响行数
        if (row <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED+"受影响的行数不等于1.");
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }
        // 查询最新信息并返回
        User lastestUser = userMapper.selectByPrimaryKey(userId);
        return lastestUser;
    }

    @Override
    public HashMap<String, String> createImage() {
        // 1.定义验证码图片名称
        String imageName = UUIDUtil.UUID_32()+".png";
        // 2.定义图形验证码的长和宽
        // 线圈干扰
//        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(130,50);
        // 圆圈干扰
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(130, 50, 4, 30);
        // 3.将图形验证码写到指定位置
//        captcha.write("/root/forum1.0/forumcheckImage/"+imageName);
//        captcha.write("D:/forumImage/"+imageName);
        captcha.write(codeimageUrl+imageName);
        // 4.得到验证码
        String code = captcha.getCode();
        HashMap<String,String> resultMap = new HashMap<>();
//        resultMap.put("imageName","./codeimg/"+imageName);
        resultMap.put("imageName",codemapperUrl+imageName);
        resultMap.put("code",code);
        return resultMap;
    }
}
